package redis;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import util.RedisUtil;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 缓存锁
 *
 * @author zhanglinfeng
 * @date create in 2022/8/31 11:17
 */
@Aspect
public class RedisLockAspect implements Ordered {
    private static Logger LOGGER = LoggerFactory.getLogger(RedisLockAspect.class);
    @Resource
    private RedissonClient redissonClient;

    @Override
    public int getOrder() {
        return 1;
    }

    @Pointcut("@annotation(redis.RedisLock)")
    public void pointcut() {
    }

    @Before(value = "pointcut()&&@annotation(redisLock)")
    public void before(JoinPoint point, RedisLock redisLock) throws Exception {
        //获取锁
        RLock rLock = getRLock(point, redisLock);
        if (rLock.isLocked()) {
            throw new Exception(redisLock.memo());
        }
        long cacheExpire = redisLock.cacheExpire();
        if (0 == cacheExpire) {
            rLock.lock();
        }
        //到时间自行释放
        rLock.lock(cacheExpire, TimeUnit.MILLISECONDS);
        LOGGER.info("加锁:{}，失效时间：{}", rLock.getName(), cacheExpire);
    }

    @After(value = "pointcut()&&@annotation(redisLock)")
    public void after(JoinPoint point, RedisLock redisLock) {
        //获取锁
        RLock rLock = getRLock(point, redisLock);
        long cacheExpire = redisLock.cacheExpire();
        if (0 == cacheExpire && rLock.isLocked()) {
            rLock.unlock();
        }
    }

    private RLock getRLock(JoinPoint point, RedisLock redisLock) {
        Object[] args = point.getArgs();
        //获取缓存key
        String cacheKey = RedisUtil.getKey(args, redisLock.cacheKey(), redisLock.cacheIndex());
        //获取锁
        return redissonClient.getLock(cacheKey);
    }
}
